/**
  ******************************************************************************
  * @file    operation_protocol.c
  * @brief   运营平台协议处理
  ******************************************************************************
  */

#include "../sdk/core/utils/core_itcp.h"

#include "../sdk/core/aiot_itcp_api.h"
#include "../sdk/core/aiot_sysdep_api.h"
#include "../sdk/core/aiot_state_api.h"

#include "../external/external.h"

#include "operation_protocol.h"
#include "operation_interface.h"

//#define OPERATION_DEBUG

#if defined(OPERATION_DEBUG)
#define OPERATION_TRACE(...)       \
    do                             \
    {                              \
        ops_printf("\033[1;34m");  \
        ops_printf(__VA_ARGS__);   \
        ops_printf("\033[0m\r\n"); \
    } while (0)
#else
#define OPERATION_TRACE(...)
#endif

/* 位于 portfiles/aiot_port 文件夹下的系统适配函数集合 */
extern aiot_sysdep_portfile_t g_aiot_sysdep_portfile;

/* 序列号，范围 [0-65535] */
static uint16_t s_seq_number;

/* 运营平台实例指针 */
static core_itcp_handle_t *s_gun_itcp_handle[OPS_MAX_PORT_NUM];

/* 日志回调函数, SDK的日志会从这里输出 */
static int32_t user_state_logcb(int32_t code, char *message)
{
    (void)code;

    OPERATION_TRACE("%s", message);

    return 0;
}

static int32_t active_service_start_charging_app(uint8_t gunno, const uint8_t *request, uint8_t **response, uint32_t *response_len)
{
    (void)gunno;
    (void)response;
    (void)response_len;

    int32_t _res = 0;
    void *callback = NULL;

    ops_active_service_start_charging_app_t ops_active_service_start_charging_app;
    ops_active_service_feedback_start_charging_app_t ops_active_service_feedback_start_charging_app;

    memcpy(&ops_active_service_start_charging_app, request, sizeof(ops_active_service_start_charging_app));

    callback = ops_service_callback(OPS_ACTIVE_SERVICE_START_CHARGING_APP);
    if (callback) {
        ((int32_t (*)(ops_active_service_start_charging_app_t *request, ops_active_service_feedback_start_charging_app_t *feedback))callback)
                (&ops_active_service_start_charging_app, &ops_active_service_feedback_start_charging_app);

        ops_active_service_feedback_start_charging_app.head.magin   = OPS_MAGIC;
        ops_active_service_feedback_start_charging_app.head.length  =
                sizeof(ops_active_service_feedback_start_charging_app_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
        ops_active_service_feedback_start_charging_app.head.seq     = s_seq_number++;
        ops_active_service_feedback_start_charging_app.head.encrypt = OPS_ENCRYPT_FLAG;
        ops_active_service_feedback_start_charging_app.head.opcode  = 0x33; /* 仅被动应答 */

        ops_active_service_feedback_start_charging_app.crc = crc16_modbus(0xFFFF, (uint8_t *)&(ops_active_service_feedback_start_charging_app.head.seq),
                sizeof(ops_active_service_feedback_start_charging_app) - 1 - 1 - 2); /* ... - magin - length - crc */

        _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL,
                (uint8_t *)(&ops_active_service_feedback_start_charging_app), sizeof(ops_active_service_feedback_start_charging_app));
    }

    return _res;
}

static int32_t active_service_stop_charging_app(uint8_t gunno, const uint8_t *request, uint8_t **response, uint32_t *response_len)
{
    (void)gunno;
    (void)response;
    (void)response_len;

    int32_t _res = 0;
    void *callback = NULL;

    ops_active_service_stop_charging_app_t ops_active_service_stop_charging_app;
    ops_active_service_feedback_stop_charging_app_t ops_active_service_feedback_stop_charging_app;

    memcpy(&ops_active_service_stop_charging_app, request, sizeof(ops_active_service_stop_charging_app));

    callback = ops_service_callback(OPS_ACTIVE_SERVICE_STOP_CHARGING_APP);
    if (callback) {
        ((int32_t (*)(ops_active_service_stop_charging_app_t *request, ops_active_service_feedback_stop_charging_app_t *feedback))callback)
                (&ops_active_service_stop_charging_app, &ops_active_service_feedback_stop_charging_app);

        ops_active_service_feedback_stop_charging_app.head.magin   = OPS_MAGIC;
        ops_active_service_feedback_stop_charging_app.head.length  =
                sizeof(ops_active_service_feedback_stop_charging_app_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
        ops_active_service_feedback_stop_charging_app.head.seq     = s_seq_number++;
        ops_active_service_feedback_stop_charging_app.head.encrypt = OPS_ENCRYPT_FLAG;
        ops_active_service_feedback_stop_charging_app.head.opcode  = 0x35; /* 仅被动应答 */

        ops_active_service_feedback_stop_charging_app.crc = crc16_modbus(0xFFFF, (uint8_t *)(&(ops_active_service_feedback_stop_charging_app.head.seq)),
                sizeof(ops_active_service_feedback_stop_charging_app) - 1 - 1 - 2); /* ... - magin - length - crc */

        _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL,
                (uint8_t *)(&ops_active_service_feedback_stop_charging_app), sizeof(ops_active_service_feedback_stop_charging_app));
    }

    return _res;
}

static int32_t active_service_fee_strategy(uint8_t gunno, const uint8_t *request, uint8_t **response, uint32_t *response_len)
{
    (void)gunno;
    (void)response;
    (void)response_len;

    int32_t _res = 0;
    void *callback = NULL;

    ops_passive_service_fee_strategy_t ops_passive_service_fee_strategy;
    ops_active_service_feedback_fee_strategy_t ops_active_service_feedback_fee_strategy;

    memcpy(&ops_passive_service_fee_strategy, request, sizeof(ops_passive_service_fee_strategy));

    callback = ops_service_callback(OPS_ACTICE_SERVICE_FEE_STRATEGY);
    if (callback) {
        ((int32_t (*)(ops_passive_service_fee_strategy_t *request, ops_active_service_feedback_fee_strategy_t *feedback))callback)
                (&ops_passive_service_fee_strategy, &ops_active_service_feedback_fee_strategy);

        ops_active_service_feedback_fee_strategy.head.magin   = OPS_MAGIC;
        ops_active_service_feedback_fee_strategy.head.length  =
                sizeof(ops_active_service_feedback_fee_strategy_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
        ops_active_service_feedback_fee_strategy.head.seq     = s_seq_number++;
        ops_active_service_feedback_fee_strategy.head.encrypt = OPS_ENCRYPT_FLAG;
        ops_active_service_feedback_fee_strategy.head.opcode  = 0x57; /* 仅被动应答 */

        ops_active_service_feedback_fee_strategy.crc = crc16_modbus(0xFFFF, (uint8_t *)(&(ops_active_service_feedback_fee_strategy.head.seq)),
                sizeof(ops_active_service_feedback_fee_strategy) - 1 - 1 - 2); /* ... - magin - length - crc */

        _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL,
                (uint8_t *)(&ops_active_service_feedback_fee_strategy), sizeof(ops_active_service_feedback_fee_strategy));
    }

    return _res;
}

static int32_t active_service_time_syn(uint8_t gunno, const uint8_t *request, uint8_t **response, uint32_t *response_len)
{
    (void)gunno;
    (void)response;
    (void)response_len;

    int32_t _res = 0;
    void *callback = NULL;

    ops_active_service_time_syn_t ops_active_service_time_syn;
    ops_active_service_feedback_time_syn_t ops_active_service_feedback_time_syn;

    memcpy(&ops_active_service_time_syn, request, sizeof(ops_active_service_time_syn));

    callback = ops_service_callback(OPS_ACTIVE_SERVICE_TIME_SYN);
    if (callback) {
        ((int32_t (*)(ops_active_service_time_syn_t *request, ops_active_service_feedback_time_syn_t *feedback))callback)
                (&ops_active_service_time_syn, &ops_active_service_feedback_time_syn);

        ops_active_service_feedback_time_syn.head.magin   = OPS_MAGIC;
        ops_active_service_feedback_time_syn.head.length  =
                sizeof(ops_active_service_feedback_time_syn_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
        ops_active_service_feedback_time_syn.head.seq     = s_seq_number++;
        ops_active_service_feedback_time_syn.head.encrypt = OPS_ENCRYPT_FLAG;
        ops_active_service_feedback_time_syn.head.opcode  = 0x55; /* 仅被动应答 */

        ops_active_service_feedback_time_syn.crc = crc16_modbus(0xFFFF, (uint8_t *)&(ops_active_service_feedback_time_syn.head.seq),
                sizeof(ops_active_service_feedback_time_syn) - 1 - 1 - 2); /* ... - magin - length - crc */

        _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL,
                (uint8_t *)(&ops_active_service_feedback_time_syn), sizeof(ops_active_service_feedback_time_syn));
    }

    return _res;
}

static int32_t active_service_reboot(uint8_t gunno, const uint8_t *request, uint8_t **response, uint32_t *response_len)
{
    (void)gunno;
    (void)response;
    (void)response_len;

    int32_t _res = 0;
    void *callback = NULL;

    ops_active_service_reboot_t ops_active_service_reboot;
    ops_active_service_feedback_reboot_t ops_active_service_feedback_reboot;

    memcpy(&ops_active_service_reboot, request, sizeof(ops_active_service_reboot));

    callback = ops_service_callback(OPS_ACTIVE_SERVICE_REBOOT);
    if (callback) {
        ((int32_t (*)(ops_active_service_reboot_t *request, ops_active_service_feedback_reboot_t *feedback))callback)
                (&ops_active_service_reboot, &ops_active_service_feedback_reboot);

        ops_active_service_feedback_reboot.head.magin   = OPS_MAGIC;
        ops_active_service_feedback_reboot.head.length  =
                sizeof(ops_active_service_feedback_reboot_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
        ops_active_service_feedback_reboot.head.seq     = s_seq_number++;
        ops_active_service_feedback_reboot.head.encrypt = OPS_ENCRYPT_FLAG;
        ops_active_service_feedback_reboot.head.opcode  = 0x91; /* 仅被动应答 */

        ops_active_service_feedback_reboot.crc = crc16_modbus(0xFFFF, (uint8_t *)&(ops_active_service_feedback_reboot.head.seq),
                sizeof(ops_active_service_feedback_reboot) - 1 - 1 - 2); /* ... - magin - length - crc */

        _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL,
                (uint8_t *)(&ops_active_service_feedback_reboot), sizeof(ops_active_service_feedback_reboot));
    }

    return _res;
}

static int32_t active_service_start_update(uint8_t gunno, const uint8_t *request, uint8_t **response, uint32_t *response_len)
{
    (void)gunno;
    (void)response;
    (void)response_len;

    int32_t _res = 0;
    void *callback = NULL;

    ops_active_service_start_update_t ops_active_service_start_update;
    ops_active_service_feedback_start_update_t ops_active_service_feedback_start_update;

    memcpy(&ops_active_service_start_update, request, sizeof(ops_active_service_start_update));

    callback = ops_service_callback(OPS_ACTIVE_SERVICE_START_UPDATE);
    if (callback) {
        ((int32_t (*)(ops_active_service_start_update_t *request, ops_active_service_feedback_start_update_t *feedback))callback)
                (&ops_active_service_start_update, &ops_active_service_feedback_start_update);
    }

    return _res;
}

static int32_t passive_service_sign_in(uint8_t gunno, const uint8_t *request, uint8_t **response, uint32_t *response_len)
{
    (void)gunno;
    (void)response;
    (void)response_len;

    int32_t _res = 0;
    void *callback = NULL;

    ops_passive_service_sign_in_t ops_passive_service_sign_in;

    memcpy(&ops_passive_service_sign_in, request, sizeof(ops_passive_service_sign_in));

    callback = ops_service_callback(OPS_PASSIVE_SERVICE_SIGN_IN);
    if (callback) {
        ((int32_t (*)(ops_passive_service_sign_in_t *request, void *feedback))callback)
                (&ops_passive_service_sign_in, NULL);
    }

    return _res;
}

static int32_t passive_service_heartbeat(uint8_t gunno, const uint8_t *request, uint8_t **response, uint32_t *response_len)
{
    (void)gunno;
    (void)response;
    (void)response_len;

    int32_t _res = 0;
    void *callback = NULL;

    ops_passive_service_heartbeat_t ops_passive_service_heartbeat;

    memcpy(&ops_passive_service_heartbeat, request, sizeof(ops_passive_service_heartbeat));

    callback = ops_service_callback(OPS_PASSIVE_SERVICE_HEARTBEAT);
    if (callback) {
        ((int32_t (*)(ops_passive_service_heartbeat_t *request, void *feedback))callback)
                (&ops_passive_service_heartbeat, NULL);
    }

    return _res;
}

static int32_t passive_service_fee_check(uint8_t gunno, const uint8_t *request, uint8_t **response, uint32_t *response_len)
{
    (void)gunno;
    (void)response;
    (void)response_len;

    int32_t _res = 0;
    void *callback = NULL;

    ops_passive_service_fee_mode_check_t ops_passive_service_fee_check;

    memcpy(&ops_passive_service_fee_check, request, sizeof(ops_passive_service_fee_check));

    callback = ops_service_callback(OPS_PASSIVE_SERVICE_FEE_CHECK);
    if (callback) {
        ((int32_t (*)(ops_passive_service_fee_mode_check_t *request, void *feedback))callback)
                (&ops_passive_service_fee_check, NULL);
    }

    return _res;
}

static int32_t passive_service_fee_strategy(uint8_t gunno, const uint8_t *request, uint8_t **response, uint32_t *response_len)
{
    (void)gunno;
    (void)response;
    (void)response_len;

    int32_t _res = 0;
    void *callback = NULL;

    ops_passive_service_fee_strategy_t ops_active_or_passive_service_fee_strategy;

    memcpy(&ops_active_or_passive_service_fee_strategy, request, sizeof(ops_active_or_passive_service_fee_strategy));

    callback = ops_service_callback(OPS_PASSIVE_SERVICE_FEE_STRATEGY);
    if (callback) {
        ((int32_t (*)(ops_passive_service_fee_strategy_t *request, void *feedback))callback)
                (&ops_active_or_passive_service_fee_strategy, NULL);
    }

    return _res;
}

static int32_t passive_service_bill(uint8_t gunno, const uint8_t *request, uint8_t **response, uint32_t *response_len)
{
    (void)gunno;
    (void)response;
    (void)response_len;

    int32_t _res = 0;
    void *callback = NULL;

    ops_passive_service_bill_t ops_passive_service_bill;

    memcpy(&ops_passive_service_bill, request, sizeof(ops_passive_service_bill));

    callback = ops_service_callback(OPS_PASSIVE_SERVICE_BILL);
    if (callback) {
        ((int32_t (*)(ops_passive_service_bill_t *request, void *feedback))callback)
                (&ops_passive_service_bill, NULL);
    }

    return _res;
}

static int32_t passive_service_card_auth(uint8_t gunno, const uint8_t *request, uint8_t **response, uint32_t *response_len)
{
    (void)gunno;
    (void)response;
    (void)response_len;

    int32_t res = 0;
    void *callback = NULL;

    ops_passive_service_card_authorize_t ops_passive_service_apply_for_charging;

    memcpy(&ops_passive_service_apply_for_charging, request, sizeof(ops_passive_service_apply_for_charging));

    callback = ops_service_callback(OPS_PASSIVE_SERVICE_CARD_AUTH);
    if(callback) {
        ((int32_t (*)(ops_passive_service_card_authorize_t *request, void *feedback))callback)
                (&ops_passive_service_apply_for_charging, NULL);
    }

    return res;
}

/**
 * @brief 服务回调：接收服务器下发的服务请求（包括应答）
 *---
 * @param [in] request: @n 请求数据.
 * @param [in] request_len: @n 请求数据长度.
 * @param [in] response: @n 响应数据.
 * @param [in] response_len: @n 响应数据长度.
 * @return None.
 * @see None.
 * @note None.
 */
static void ops_service_request(uint8_t gunno, const uint8_t *request, const uint32_t request_len, uint8_t **response, uint32_t *response_len)
{
    if ((NULL == request) || (6 + 2 > request_len)) /* head + crc */
    {
        return;
    }

    uint8_t opcode = (*(request + 5));

    switch (opcode) {
    case OPS_ACTIVE_SERVICE_START_CHARGING_APP:
        active_service_start_charging_app(gunno, request, response, response_len);
        break;
    case OPS_ACTIVE_SERVICE_STOP_CHARGING_APP:
        active_service_stop_charging_app(gunno, request, response, response_len);
        break;
    case OPS_ACTIVE_SERVICE_CARD_SYN:
        break;
    case OPS_ACTIVE_SERVICE_CARD_CLEAR:
        break;
    case OPS_ACTIVE_SERVICE_CARD_QUERY:
        break;
    case OPS_ACTICE_SERVICE_FEE_STRATEGY:
        active_service_fee_strategy(gunno, request, response, response_len);
        break;
    case OPS_ACTIVE_SERVICE_TIME_SYN:
        active_service_time_syn(gunno, request, response, response_len);
        break;
    case OPS_ACTIVE_SERVICE_REBOOT:
        active_service_reboot(gunno, request, response, response_len);
        break;
    case OPS_ACTIVE_SERVICE_START_UPDATE:
        active_service_start_update(gunno, request, response, response_len);
        break;
    case OPS_PASSIVE_SERVICE_FEE_CHECK:
        passive_service_fee_check(gunno, request, response, response_len);
        break;
    case OPS_PASSIVE_SERVICE_SIGN_IN:
        passive_service_sign_in(gunno, request, response, response_len);
        break;
    case OPS_PASSIVE_SERVICE_HEARTBEAT:
        passive_service_heartbeat(gunno, request, response, response_len);
        break;
    case OPS_PASSIVE_SERVICE_FEE_STRATEGY:
        passive_service_fee_strategy(gunno, request, response, response_len);
        break;
    case OPS_PASSIVE_SERVICE_BILL:
        passive_service_bill(gunno, request, response, response_len);
        break;
    case OPS_PASSIVE_SERVICE_CARD_AUTH:
        passive_service_card_auth(gunno, request, response, response_len);
    default:
        break;
    }
}

/**
 * @brief ITCP事件回调函数, 当SDK读取到网络报文时被触发
 *---
 * @param [in] handle: @n 实例句柄.
 * @param [in] packet: @n 请求数据包.
 * @param [in] userdata: @n 用户数据.
 * @return None.
 * @see None.
 * @note None.
 */
static void ops_itcp_recv_handler(void *handle, const aiot_itcp_recv_t *packet, void *userdata)
{
    (void)userdata;

    int8_t index;
    uint8_t gunno = 0;
    core_itcp_handle_t *itcp_handle = (core_itcp_handle_t *)handle;

    for(index = 0; index < OPS_MAX_PORT_NUM; index++)
    {
        if(itcp_handle == s_gun_itcp_handle[index])
        {
            gunno = index + OPSGUNNOA;
        }
    }

    switch (packet->type)
    {
        case AIOT_ITCPRECV_STATUS_CODE:
            break;
        case AIOT_ITCPRECV_HEADER:
            break;
        case AIOT_ITCPRECV_BODY:
            ops_service_request(gunno, packet->data.body.buffer, packet->data.body.len, NULL, NULL);
            break;
        default:
            break;
    }
}

static int32_t send_event_update_res(ops_active_service_feedback_start_update_t *data)
{
    int32_t _res = 0;

    data->head.magin    = OPS_MAGIC;
    data->head.length   = sizeof(ops_active_service_feedback_start_update_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq      = s_seq_number++;
    data->head.encrypt  = OPS_ENCRYPT_FLAG;
    data->head.opcode   = OPS_CMD_EVENT_UPDATE_RES;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_active_service_feedback_start_update_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_active_service_feedback_start_update_t));

    return _res;
}

static int32_t send_event_apply_for_charging(uint8_t gunno, ops_event_card_authorize_t *data)
{
    int32_t _res = 0;

    data->head.magin    = OPS_MAGIC;
    data->head.length   = sizeof(ops_event_card_authorize_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq      = s_seq_number++;
    data->head.encrypt  = OPS_ENCRYPT_FLAG;
    data->head.opcode   = OPS_CMD_EVENT_CARD_AUTH;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_card_authorize_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_card_authorize_t));

    return _res;
}

static int32_t send_event_bill(uint8_t gunno, ops_event_bill_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_event_bill_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_EVENT_BILL;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_bill_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_bill_t));

    return _res;
}

static int32_t send_event_fee_strategy( ops_event_fee_strategy_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_event_fee_strategy_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_EVENT_FEE_STRATEGY;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_fee_strategy_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_fee_strategy_t));

    return _res;
}

static int32_t send_event_sign_in(uint8_t gunno, ops_event_sign_in_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_event_sign_in_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_EVENT_SIGN_IN;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_sign_in_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_sign_in_t));

    return _res;
}


static int32_t send_event_check_fee(ops_event_fee_mode_check_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_event_fee_mode_check_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_EVENT_CHECK_FEE;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_fee_mode_check_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_fee_mode_check_t));

    return _res;
}

static int32_t send_event_handshake( ops_event_charge_handshake_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_event_charge_handshake_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_EVENT_HANDSHAKE;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_charge_handshake_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_charge_handshake_t));

    return _res;
}

static int32_t send_event_set_value( ops_event_set_value_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_event_set_value_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_EVENT_SET_VALUE;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_set_value_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_set_value_t));

    return _res;
}


static int32_t send_event_charge_complete( ops_event_charge_complete_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_event_charge_complete_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_EVENT_CHARGE_COMPLETE;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_charge_complete_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_charge_complete_t));

    return _res;
}


static int32_t send_event_error( ops_event_error_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_event_error_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_EVENT_ERROR;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_error_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_error_t));

    return _res;
}


static int32_t send_event_charge_abort( ops_event_charge_abort_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_event_charge_abort_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_EVENT_CHARGE_ABORT;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_charge_abort_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_charge_abort_t));

    return _res;
}

static int32_t send_event_charge_stop(ops_event_charge_stop_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_event_charge_stop_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_EVENT_CHARGE_STOP;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_charge_stop_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_charge_stop_t));

    return _res;
}

static int32_t send_event_charge_output(ops_event_charge_output_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_event_charge_output_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_EVENT_CHARGE_OUTPUT;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_charge_output_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_charge_output_t));

    return _res;
}


static int32_t send_event_charge_process_(ops_event_charge_process_status_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_event_charge_process_status_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_EVENT_CHARGE_PROCESS_STATUS;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_charge_process_status_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_charge_process_status_t));

    return _res;
}

static int32_t send_event_heartbeat(uint8_t gunno, ops_event_heartbeat_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_event_heartbeat_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_EVENT_HEARTBEAT;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_event_heartbeat_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_event_heartbeat_t));

    return _res;
}

static int32_t send_property_charge_data(uint8_t gunno, ops_property_charge_data_t *data)
{
    int32_t _res = 0;

    data->head.magin   = OPS_MAGIC;
    data->head.length  = sizeof(ops_property_charge_data_t) - sizeof(ops_head_t) + 2 + 1 + 1 - 2; /* ... + seq + encrypt + opcode - crc */
    data->head.seq     = s_seq_number++;
    data->head.encrypt = OPS_ENCRYPT_FLAG;
    data->head.opcode  = OPS_CMD_PROPERTY_CHARG_DATA;

    data->crc = crc16_modbus(0xFFFF, (uint8_t *)(&(data->head.seq)), sizeof(ops_property_charge_data_t) - 1 - 1 - 2); /* ... - magin - length - crc */

    _res = aiot_itcp_send(s_gun_itcp_handle[0], NULL, (uint8_t *)data, sizeof(ops_property_charge_data_t));

    return _res;
}

/**
 * @brief init handle.
 *---
 * @param ops_eth, ops_host, ops_port
 * @return do not free -1, free 0.
 * @see None.
 * @note None.
 */
int32_t ops_linkkit_new(char *ops_eth, char *ops_host, uint16_t ops_port)
{
    int8_t index = 0;

    if(NULL == ops_host)
    {
        return -1;
    }

    for(index = 0; index < OPS_MAX_PORT_NUM; index++)
    {
        s_gun_itcp_handle[index] = NULL;
    }

    /* 配置SDK的底层依赖 */
    aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile);

    /* 配置SDK的日志输出 */
    aiot_state_set_logcb(user_state_logcb);

     index = 0;

        /* 创建ITCP客户端实例并内部初始化默认参数 */
        s_gun_itcp_handle[0] = aiot_itcp_init();
        if (NULL == s_gun_itcp_handle[0])
        {
            return -1;
        }

        /* 配置网络接口 */
//        aiot_itcp_setopt(s_gun_itcp_handle[index], AIOT_ITCPOPT_ETH, (void *)ops_eth);

        /* 配置服务器域名 */
        aiot_itcp_setopt(s_gun_itcp_handle[0], AIOT_ITCPOPT_HOST, (void *)ops_host);

        /* 配置服务器端口 */
        aiot_itcp_setopt(s_gun_itcp_handle[0], AIOT_ITCPOPT_PORT, (void *)&ops_port);

        /* 配置数据到达时, SDK应调用的用户回调函数 */
        aiot_itcp_setopt(s_gun_itcp_handle[0], AIOT_ITCPOPT_RECV_HANDLER, ops_itcp_recv_handler);

    return 0;
}

/**
 * @brief free handle.
 *---
 * @param None.
 * @return do not free -1, free 0.
 * @see None.
 * @note None.
 */
int32_t ops_linkkit_free(void)
{
    int8_t index;

    for(index = 0; index < OPS_MAX_PORT_NUM; index++)
    {
        aiot_itcp_deinit((void *)&s_gun_itcp_handle[index]);
    }

    return 0;
}

/**
 * @brief network deinit.
 *---
 * @param None.
 * @return core_sysdep_network_deinit().
 * @see None.
 * @note None.
 */
int32_t ops_network_deinit(uint8_t gunno)
{
    if((gunno < OPSGUNNOA) || (gunno >= OPSGUNNOA + OPS_MAX_PORT_NUM))
    {
        return -1;
    }

    gunno = 1;

    if (NULL == s_gun_itcp_handle[0])
    {
        return -1;
    }

    return s_gun_itcp_handle[0]->sysdep->core_sysdep_network_deinit(&s_gun_itcp_handle[0]->network_handle);
}

/**
 * @brief device authentication.
 *---
 * @param [in] param: @n the auth data will be written.
 * @param [in] len: @n the auth data len will be written.
 * @return do not free -1, free 0.
 * @see None.
 * @note None.
 */
int32_t ops_auth(uint8_t gunno, void *param, uint32_t len)
{
    if((gunno < OPSGUNNOA) || (gunno >= OPSGUNNOA + OPS_MAX_PORT_NUM))
    {
        return -1;
    }

    if (NULL == s_gun_itcp_handle[0])
    {
        return -1;
    }

    return aiot_itcp_auth(s_gun_itcp_handle[0], param, len);
}

/**
 * @brief yield.
 *---
 * @param None.
 * @return aiot_itcp_recv().
 * @see None.
 * @note None.
 */
int32_t ops_yield(uint8_t gunno)
{
    if((gunno < OPSGUNNOA) || (gunno >= OPSGUNNOA + OPS_MAX_PORT_NUM))
    {
        return -1;
    }

    if (NULL == s_gun_itcp_handle[0])
    {
        return -1;
    }

    return aiot_itcp_recv(s_gun_itcp_handle[0]);
}

/**
 * @brief 发送桩事件数据发送到运营平台.
 *---
 * @param [in] event_type: @n the event you want to send.
 * @param [in] param: @n the event data will be written.
 * @return None.
 * @see None.
 * @note None.
 */
void ops_send_event(uint8_t gunno, ops_cmd_event_enum event_type, void *param)
{
    if((gunno < OPSGUNNOA) || (gunno >= OPSGUNNOA + OPS_MAX_PORT_NUM))
    {
        return;
    }

    gunno = 1;

    switch (event_type) {
    case OPS_CMD_EVENT_SIGN_IN:
        send_event_sign_in(gunno, (ops_event_sign_in_t *)param);
        break;
    case OPS_CMD_EVENT_CHECK_FEE:
        send_event_check_fee((ops_event_fee_mode_check_t *)param);
        break;
    case OPS_CMD_EVENT_HEARTBEAT:
        send_event_heartbeat(gunno, (ops_event_heartbeat_t *)param);
        break;
    case OPS_CMD_EVENT_FEE_STRATEGY:
        send_event_fee_strategy( (ops_event_fee_strategy_t *)param);
        break;
    case OPS_CMD_EVENT_CARD_AUTH:
        send_event_apply_for_charging(gunno, (ops_event_card_authorize_t *)param);
        break;
    case OPS_CMD_EVENT_BILL:
        send_event_bill(gunno, (ops_event_bill_t *)param);
        break;
    case OPS_CMD_EVENT_UPDATE_RES:
        send_event_update_res( (ops_active_service_feedback_start_update_t *)param);
        break;
    case OPS_CMD_EVENT_HANDSHAKE:
        send_event_handshake((ops_event_charge_handshake_t *)param);
        break;
    case OPS_CMD_EVENT_SET_VALUE:
        send_event_set_value((ops_event_set_value_t *)param);
        break;
    case OPS_CMD_EVENT_CHARGE_COMPLETE:
        send_event_charge_complete((ops_event_charge_complete_t *)param);
        break;
    case OPS_CMD_EVENT_ERROR:
        send_event_error((ops_event_error_t *)param);
        break;
    case OPS_CMD_EVENT_CHARGE_ABORT:
        send_event_charge_abort((ops_event_charge_abort_t *)param);
        break;
    case OPS_CMD_EVENT_CHARGE_STOP:
        send_event_charge_stop((ops_event_charge_stop_t *)param);
        break;
    case OPS_CMD_EVENT_CHARGE_OUTPUT:
        send_event_charge_output((ops_event_charge_output_t *)param);
        break;
    case OPS_CMD_EVENT_CHARGE_PROCESS_STATUS:
        send_event_charge_process_((ops_event_charge_process_status_t *)param);
        break;
    default:
        break;
    }
}

/**
 * @brief 发送桩属性数据发送到运营平台.
 * @param [in] event_type: @n the property you want to send.
 * @param [in] param: @n the property data will be written.
 * @return None.
 * @see None.
 * @note None.
 */
void ops_send_property(uint8_t gunno, ops_cmd_property_enum property_type, void *param)
{
    if((gunno < OPSGUNNOA) || (gunno >= OPSGUNNOA + OPS_MAX_PORT_NUM))
    {
        return;
    }
    gunno = 1;
    switch (property_type) {
    case OPS_CMD_PROPERTY_CHARG_DATA:
        send_property_charge_data(gunno, (ops_property_charge_data_t *)param);
        break;
    default:
        break;
    }
}
